﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.IO;
using SyncList.Business;
using SyncList.Business.ValueObject;
using SyncList.Business.Persistence;
using SyncList.UserInterface;
using SyncList.Business.Helpers;
using System.Threading;

namespace SyncList.Win
{
	/// <summary>
	/// Interaction logic for WindowCopy.xaml
	/// </summary>
	public partial class WindowCopy : Window
	{

        /// <summary>
        /// Dossier cible de base 
        /// </summary>
        private string _targetBase = "";



        /// <summary>
        /// Constructeur
        /// </summary>
		public WindowCopy()
		{
			this.InitializeComponent();

            StartHelper.Start(MenuBar);
            MenuBar.ExitAction = () => this.Close();

            this.BlockLoad.AllowDrop = true;
            this.BlockLoad.Drop += new DragEventHandler(BlockLoad_Drop);
            this.BtnCopy.Click += new RoutedEventHandler(BtnCopy_Click);
		}





        /// <summary>
        /// Drop d'une liste dans la zone
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void BlockLoad_Drop(object sender, DragEventArgs e)
        {
            //Récupère le path du fichier que l'on vient de glisser-déposer sur l'interface de comparaison !
            string[] _filePath = (string[])e.Data.GetData(DataFormats.FileDrop);
            if (_filePath == null || !_filePath.Count().Equals(1))
                return;

            if (!File.Exists(_filePath[0]))
                return;

            //on récupère un FileInfo sur le fichier qui vient d'être déposé.
            FileInfo _currentFileDropped = new FileInfo(_filePath[0]);

            // On vérifie que le fichier est bien au format XML
            if (!_currentFileDropped.Extension.ToLower().Equals(".syw"))
            {
                MessageBox.Show("This is not a SyncList wishes file !");
                return;
            }

            LoadFile(_currentFileDropped.FullName);
        }



        /// <summary>
        /// Charger le fichier
        /// </summary>
        /// <param name="fileName">Nom et chemin du fichier</param>
        private void LoadFile(string fileName)
        {
            DirectoryContent root = ucExplorer.Root;
            ServiceAccessor.ImportService.ImportWishes(root, fileName);

            string currentUserName = MemoryStorage.Instance.Settings.UserName;

            // - Vérifier si l'on a le fichier
            foreach (FileItem file in root.AllFiles)
            {
                bool success = false;

                if (file.UserName == currentUserName)
                {
                    if (Directory.Exists(file.LocalFolder))
                    {
                        string fullPath = file.LocalFolder;
                        if (!fullPath.EndsWith(@"\"))
                            fullPath += @"\";
                        fullPath += file.Name;
                        if (File.Exists(fullPath))
                            success = true;
                    }
                }
                if (success)
                    file.State = ExplorerItemState.IHaveFile;
                else
                    file.State = ExplorerItemState.ICantGiveThisFile;
                    
            }

            ServiceAccessor.FusionService.CheckDirectoriesStates(root);

            ucExplorer.Data.Refresh();
        }



        /// <summary>
        /// Copier
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void BtnCopy_Click(object sender, RoutedEventArgs e)
        {
            string target = this.TextBoxTarget.Text;
            if (String.IsNullOrWhiteSpace(target))
            {
                MessageBox.Show("Vous devez spécifier un dossier cible valide");
                return;
            }
            if (!Directory.Exists(target))
            {
                MessageBox.Show("Le dossier cible n'a pas été trouvé. Veuillez saisir un dossier valide.");
                return;
            }
            _targetBase = target;

            ThreadStart start = new ThreadStart(CopyAll);
            Thread thread = new Thread(start);
            thread.Start();
        }



        /// <summary>
        /// Copier tous les fichiers demandés et connus
        /// </summary>
        /// <param name="targetBase">Dossier de base</param>
        private void CopyAll()
        {
            string targetBase = _targetBase;
            if (!Directory.Exists(targetBase))
                return;

            DirectoryContent root = ucExplorer.Data.Root;
            List<FileItem> files = root.AllFiles.Where(f => f.State == ExplorerItemState.IHaveFile).ToList();
            

            // - Je sais qu'il existe Sum mais j'aimerais pratiquer un peu Aggregate
            long totalSize = files.Aggregate<FileItem, long>(0, (previousValue, file) => previousValue + file.Size);
            int totalFileCount = files.Count;            

            long currentSize = 0;
            int currentFileCount = 0;
            ExecuteUIAndWait(delegate()
               {
                   UpdateProgress(currentSize, totalSize, currentFileCount, totalFileCount);
               });


            foreach (FileItem file in files)
            {
                // - Copier
                string sourcePath = file.LocalFolder;
                if (!sourcePath.EndsWith("\\"))
                    sourcePath += "\\";

                string[] pathParts = sourcePath.Split('\\');
                string sourceFileName = sourcePath + file.Name;

                string targetPath = targetBase;
                foreach (string pathPart in pathParts)
                {
                    if(String.IsNullOrWhiteSpace(pathPart)) continue;
                    if(pathPart.Contains(":")) continue;

                    targetPath += "\\" + pathPart;
                    if (!Directory.Exists(targetPath))
                        Directory.CreateDirectory(targetPath);
                }
                string targetFileName = targetPath + "\\" + file.Name;

                bool write = true;
                FileInfo info = new FileInfo(targetFileName);
                if(info != null)
                {
                    if (info.Exists)
                    {
                        if (info.Length == file.Size)
                            write = false;
                    }
                }

                // - Seulement si la taille est différente ou le fichier n'existe pas
                if(write)
                    File.Copy(sourceFileName, targetFileName);

                // - Afficher l'état                
                currentFileCount++;
                currentSize += file.Size;

                ExecuteUIAndWait(delegate()
                {
                    ListBoxCopie.Items.Add(file.Name);
                    UpdateProgress(currentSize, totalSize, currentFileCount, totalFileCount);
                });
            }

            ExecuteUIAndWait(delegate()
               {
                   MessageBox.Show("Copie terminée!");
               });
        }


        /// <summary>
        /// Mettre à jour l'avancement
        /// </summary>
        /// <param name="currentSize">Taille courante</param>
        /// <param name="totalSize">Taille totale</param>
        /// <param name="currentFileCount">Nombre de fichiers traités</param>
        /// <param name="totalFileCount">Nombre de fichiers au total</param>
        private void UpdateProgress(long currentSize, long totalSize, int currentFileCount, int totalFileCount)
        {           
            Progress.Maximum = totalSize;
            Progress.Value = currentSize;
            this.TextBlockProgress.Text = SizeHelper.FormatSize(currentSize) + "/" + SizeHelper.FormatSize(totalSize) + " - " + currentFileCount.ToString() + "/" + totalFileCount.ToString() + " files";
        }


        /// <summary>
        /// Exécuter une action dans le Thread UI et attendre
        /// </summary>
        /// <param name="action"></param>
        private void ExecuteUIAndWait(Action action)
        {
            ManualResetEvent semaphore = new ManualResetEvent(false);
            Dispatcher.BeginInvoke(new Action(delegate()
            {
                action();
                semaphore.Set();
            }));

            semaphore.WaitOne();
        }



	}
}